package net.xxcxcxcx.xc_enhancedmob.render.boss_bar.unit.client;

import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.util.math.MathHelper;
import net.xxcxcxcx.xc_enhancedmob.render.TextureElement;
import net.xxcxcxcx.xc_enhancedmob.render.boss_bar.unit.BaseCustomBossBar;

import java.util.concurrent.CopyOnWriteArrayList;

@Environment(EnvType.CLIENT)
public class ClientCustomBossBar extends BaseCustomBossBar implements ClientBaseCustomBossBar {

    int LastLayCount = -1, NowLayCount = -1, RealLayCount = -1;
    float LastLayerPercentage = -1, NowLayerPercentage = -1, RealLayerPercentage = -1, UpdataRange = 0.1f;

    public ClientCustomBossBar(NbtCompound nbtCompound) {
        super();
        readCustomDataFromNbt(nbtCompound);
        getUuid().setDirty(false);
        getName().setDirty(false);
        getRealityType().setDirty(false);
        getMaxCount().setDirty(false);
        getNowCount().setDirty(false);
        getLayerCount().setDirty(false);
        getNeedMeterCover().setDirty(false);
        getMeterCoverType().setDirty(false);
    }

    @Override
    public TextureElement getBackground() {
        return getRealityType().getValue().getBackground();
    }

    @Override
    public boolean isNeedMeterCover() {
        return getNeedMeterCover().getValue();
    }

    @Override
    public TextureElement getMeterCover() {
        return getMeterCoverType().getValue().getMeterCover();
    }

    public boolean hasIcon() { return getRealityType().getValue().hasIcon();}

    public TextureElement getIcon() {return  getRealityType().getValue().getIcon();}

    @Override
    public int getMeterOffsetX0() {
        return getRealityType().getValue().getMeterOffsetX0();
    }

    @Override
    public int getMeterOffsetY0() {
        return getRealityType().getValue().getMeterOffsetY0();
    }

    @Override
    public int getMeterOffsetX1() {
        return getRealityType().getValue().getMeterOffsetX1();
    }

    @Override
    public int getMeterOffsetY1() {
        return getRealityType().getValue().getMeterOffsetY1();
    }

    //获取当前血条的像素宽度
    @Override
    public int getWidth() {
        return Math.max(getBackground().getWidth(), 0);
    }

    //获取当前血条的像素高度
    @Override
    public int getHeight() {
        return Math.max(getBackground().getHeight(), 0);
    }

    @Override
    public CopyOnWriteArrayList<TextureElement> getLayers() {
        return getRealityType().getValue().getLayers();
    }

    //获取当前层的纹理
    @Override
    public TextureElement getCurrentLayerTexture(float tickDelta) {
        float perLayerNum = getMaxCount().getValue() / getLayerCount().getValue();//血条每层的数量
        int layerCount = CalculateNowLayerCount(tickDelta);//当前血条层数()
        int layerIndex = layerCount;
        if (layerCount * perLayerNum == getNowCount().getValue()) {
            layerIndex += 1;
        }//特判正好(例如初始)情况，为层数+1
        return getRealityType().getValue().getLayer(layerIndex);
    }

    //获取下一层的纹理
    @Override
    public TextureElement getNextLayerTexture(float tickDelta) {
        float perLayerNum = getMaxCount().getValue() / getLayerCount().getValue();//血条每层的数量
        int layerCount = CalculateNowLayerCount(tickDelta);//当前血条层数()
        int layerIndex = layerCount - 1;//获取下一层的编号
        if (layerCount * perLayerNum == getNowCount().getValue()) {
            layerIndex += 1;
        }//特判正好(例如初始)情况，为层数+1
        return getRealityType().getValue().getLayer(layerIndex);
    }

    //检测是否有下一层
    @Override
    public boolean hasNextLayer(float tickDelta) {
        return CalculateNowLayerCount(tickDelta) > 0;
    }

    //计算实时渲染的血条层数
    @Override
    public int CalculateNowLayerCount(float tickDelta) {
        tickDelta = 1 - tickDelta;
        int count = 0;
        float num = MathHelper.lerp(tickDelta, NowLayerPercentage, LastLayerPercentage + LastLayCount - NowLayCount);
        while (num > 1) {
            num -= 1;
            count++;
        }
        return NowLayCount + count;
    }

    //计算实时渲染的血条百分比
    @Override
    public float CalculateLayerPercentage(float tickDelta) {
        tickDelta = 1 - tickDelta;
        float num = MathHelper.lerp(tickDelta, NowLayerPercentage, LastLayerPercentage + LastLayCount - NowLayCount);
        while (num > 1) num -= 1;
        return num;
    }

    //获取当前血条层数
    @Override
    public int NowLayerCount() {
        float perLayerNum = getMaxCount().getValue() / getLayerCount().getValue();//血条每层的数量
        int layerCount = (int) (getNowCount().getValue() / perLayerNum);//当前血条层数()
        if ((getNowCount().getValue() - perLayerNum * (layerCount)) < 0.1) {
            layerCount--;
        }
        return layerCount;
    }

    //计算当前血量显示百分比
    @Override
    public float NowLayerPercentage() {
        float perLayerNum = getMaxCount().getValue() / getLayerCount().getValue();//血条每层的数量
        int layerCount = NowLayerCount();//当前血条层数()
        return Math.min((getNowCount().getValue() - perLayerNum * (layerCount)) / (perLayerNum), 1.0f);
    }

    //记录连续两帧之间的血条层数和血条显示百分比差
    @Override
    public void tick(MobEntity mobEntity) {
        if (mobEntity == null) {
            LastLayCount = NowLayCount = RealLayCount = 0;
            LastLayerPercentage = NowLayerPercentage = RealLayerPercentage = 0;
            return;
        }
        boolean f = false;
        if (RealLayCount == -1) {
            LastLayCount = NowLayCount = RealLayCount = NowLayerCount();
            LastLayerPercentage = NowLayerPercentage = RealLayerPercentage = NowLayerPercentage();
        }
        LastLayCount = NowLayCount;
        LastLayerPercentage = NowLayerPercentage;
        if (RealLayCount != NowLayerCount() || RealLayerPercentage != NowLayerPercentage()) {
            RealLayCount = NowLayerCount();
            RealLayerPercentage = NowLayerPercentage();
            f = true;
        }
        if (RealLayCount != NowLayCount || RealLayerPercentage != NowLayerPercentage) {
            UpdataRange += 0.01f;
            if (f && UpdataRange > 0.2f) UpdataRange = 0.2f;
            if (UpdataRange > 1) UpdataRange = 1;
            int count = 0;
            float num = MathHelper.lerp(1 - UpdataRange, RealLayerPercentage, NowLayerPercentage + NowLayCount - RealLayCount);
            while (num > 1) {
                num -= 1;
                count++;
            }
            NowLayCount = RealLayCount + count;
            NowLayerPercentage = num;
        } else UpdataRange = 0.01f;
    }
}
